package com.gjy.console.ssh;

import org.apache.sshd.client.channel.ChannelExec;
import org.apache.sshd.client.channel.ClientChannelEvent;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.sftp.client.SftpClient;
import org.apache.sshd.sftp.client.SftpClientFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author gjy
 * @version 1.0
 * @since 2025-09-04 18:40:00
 */
public class OperatorUtil {

    private static final String SEPARATOR = "/";

    private final ClientSession session;
    private final String charset;

    public OperatorUtil(ClientSession session) {
        this.session = session;
        this.charset = "UTF-8";
    }

    public OperatorUtil(ClientSession session, String charset) {
        this.session = session;
        this.charset = charset;
    }

    /**
     * 执行单条SSH命令
     *
     * @param command 命令字符串
     * @return 命令输出结果
     */
    public String executeCommand(String command) throws IOException {
        try (ChannelExec channel = session.createExecChannel(command)) {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ByteArrayOutputStream errorStream = new ByteArrayOutputStream();

            channel.setOut(outputStream);
            channel.setErr(errorStream);
            channel.open();
            channel.waitFor(Collections.singletonList(ClientChannelEvent.CLOSED), 0);

            int exitStatus = channel.getExitStatus();
            if (exitStatus != 0) {
                String errorMsg = errorStream.toString(charset);
                throw new RuntimeException("命令执行失败: " + errorMsg);
            }

            return outputStream.toString(charset);
        }
    }

    /**
     * 执行多条命令（按顺序执行）
     *
     * @param commands 命令列表
     * @return 命令输出结果列表
     */
    public List<String> executeCommands(List<String> commands) throws IOException {
        List<String> results = new ArrayList<>();
        for (String cmd : commands) {
            results.add(executeCommand(cmd));
        }
        return results;
    }

    /**
     * 上传本地文件到远程服务器
     * <p>
     * tail -f /var/log/secure  排查错误日志
     *
     * @param localFilePath 本地文件路径
     * @param remoteDir     远程目录路径
     */
    public void uploadFile(String localFilePath, String remoteDir) {
        Path path = Paths.get(localFilePath);
        String filename = path.getFileName().toString();
        remoteDir = remoteDir.endsWith(SEPARATOR) ? remoteDir + filename : remoteDir + SEPARATOR + filename;
        try (SftpClient client = SftpClientFactory.instance().createSftpClient(session);
             InputStream is = Files.newInputStream(path);
             OutputStream os = client.write(remoteDir, SftpClient.OpenMode.Write, SftpClient.OpenMode.Create, SftpClient.OpenMode.Truncate)) {
            // 上传文件
            IoUtils.copy(is, os);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 从远程服务器下载文件
     *
     * @param remoteFilePath 远程文件路径
     * @param localDir       本地目录路径
     */
    public void downloadFile(String remoteFilePath, String localDir, String localName) throws IOException {
        Path path = Paths.get(localDir);
        if (!Files.exists(path)) {
            Files.createDirectories(path);
        }
        Path targetFile = path.resolve(localName);

        try (SftpClient client = SftpClientFactory.instance().createSftpClient(session);
             InputStream in = client.read(remoteFilePath);
             OutputStream out = Files.newOutputStream(targetFile, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)
        ) {
            IoUtils.copy(in, out);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 递归创建远程目录
     */
    public void mkdirs(String dir) {
        try (SftpClient client = SftpClientFactory.instance().createSftpClient(session)) {
            String[] dirs = dir.split("/");
            String currentDir = "";
            for (String d : dirs) {
                if (d.isEmpty()) continue;
                currentDir += "/" + d;
                try {
                    client.stat(currentDir); // 检查目录是否存在
                } catch (IOException e) {
                    client.mkdir(currentDir); // 不存在则创建
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

}
